JPA Inheritance Mapping হলো একটি টেকনিক, যার মাধ্যমে জাভার ইনহেরিটেন্স (Inheritance) স্ট্রাকচারকে ডেটাবেস টেবিলের সঙ্গে ম্যাপ করা যায়। এটি ডেটা মডেলকে আরও কার্যকরভাবে ডিজাইন করার সুযোগ দেয়। JPA বিভিন্ন ইনহেরিটেন্স স্ট্রাটেজি সমর্থন করে, যা ডেটাবেসের কাঠামো অনুযায়ী নির্বাচন করা যায়।
JPA Inheritance Mapping-এর স্ট্রাটেজি
১. Single Table Strategy
সব ক্লাসের ডেটা একটি টেবিলে রাখা হয়। প্রতিটি ইনহেরিটেড ক্লাসের জন্য একটি আলাদা কলাম থাকে।
২. Table Per Class Strategy
প্রত্যেক সাবক্লাসের জন্য আলাদা টেবিল তৈরি হয়। অভিভাবক (Parent) ক্লাসের টেবিল থাকে না।
৩. Joined Strategy
অভিভাবক এবং প্রত্যেক সাবক্লাসের জন্য আলাদা টেবিল তৈরি হয়। Parent এবং Child টেবিলগুলো একটি সম্পর্কের (Join) মাধ্যমে যুক্ত থাকে।
JPA Inheritance Mapping অ্যানোটেশন
@Inheritance: ইনহেরিটেন্স স্ট্রাটেজি নির্ধারণের জন্য ব্যবহৃত হয়।@DiscriminatorColumn: Single Table স্ট্রাটেজির ক্ষেত্রে টেবিলে সাবক্লাস চিহ্নিত করার জন্য একটি কলাম নির্ধারণ করে।@MappedSuperclass: কোনো ক্লাসকে Entity হিসেবে চিহ্নিত না করে শুধুমাত্র ইনহেরিটেন্সের জন্য Parent হিসেবে ব্যবহার করা হয়।
উদাহরণ: JPA Inheritance Mapping
নিচে একটি উদাহরণ দেওয়া হলো যেখানে একটি Person ক্লাস Parent এবং Employee এবং Customer ক্লাস Child।
Parent Entity: Person
import jakarta.persistence.*;
@Entity
@Inheritance(strategy = InheritanceType.JOINED) // স্ট্রাটেজি: Joined
public abstract class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
// Getters and Setters
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Child Entity: Employee
import jakarta.persistence.Entity;
@Entity
public class Employee extends Person {
private String department;
// Getters and Setters
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
}
Child Entity: Customer
import jakarta.persistence.Entity;
@Entity
public class Customer extends Person {
private String membershipLevel;
// Getters and Setters
public String getMembershipLevel() {
return membershipLevel;
}
public void setMembershipLevel(String membershipLevel) {
this.membershipLevel = membershipLevel;
}
}
Database Table Mapping: Joined Strategy
Joined স্ট্রাটেজির ক্ষেত্রে ডেটাবেসে তিনটি টেবিল তৈরি হবে:
Personটেবিল:CREATE TABLE Person ( id BIGINT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(255) );Employeeটেবিল:CREATE TABLE Employee ( id BIGINT PRIMARY KEY, department VARCHAR(255), FOREIGN KEY (id) REFERENCES Person(id) );Customerটেবিল:CREATE TABLE Customer ( id BIGINT PRIMARY KEY, membershipLevel VARCHAR(255), FOREIGN KEY (id) REFERENCES Person(id) );
Repository উদাহরণ
JPA Repository ব্যবহার করে ডেটাবেস অপারেশন সম্পন্ন করা যায়:
import org.springframework.data.jpa.repository.JpaRepository;
public interface PersonRepository extends JpaRepository<Person, Long> {
// Custom query methods
}
Controller উদাহরণ
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/persons")
public class PersonController {
@Autowired
private PersonRepository personRepository;
@GetMapping
public List<Person> getAllPersons() {
return personRepository.findAll();
}
@PostMapping("/employee")
public Person addEmployee(@RequestBody Employee employee) {
return personRepository.save(employee);
}
@PostMapping("/customer")
public Person addCustomer(@RequestBody Customer customer) {
return personRepository.save(customer);
}
}
সুবিধা ও সীমাবদ্ধতা
সুবিধা:
- ডেটাবেস এবং অবজেক্ট মডেলের মধ্যে সহজ সম্পর্ক তৈরি।
- কোডের পুনরায় ব্যবহারযোগ্যতা নিশ্চিত।
- বিভিন্ন স্ট্রাটেজি প্রয়োগের মাধ্যমে পারফরম্যান্স টিউনিং।
সীমাবদ্ধতা:
- কিছু ক্ষেত্রে স্ট্রাটেজি অনুযায়ী ডেটাবেসের পারফরম্যান্স কম হতে পারে।
- Joined স্ট্রাটেজিতে কেরি জটিল হতে পারে।
সারাংশ
JPA Inheritance Mapping স্প্রিং বুটে ডেটা মডেলিংকে আরও কার্যকর করে। এর মাধ্যমে ডেটাবেসের কাঠামো এবং জাভার ইনহেরিটেড ক্লাসগুলোর মধ্যে মেলবন্ধন তৈরি করা যায়। বিভিন্ন স্ট্রাটেজি ব্যবহার করে আপনার প্রজেক্টের চাহিদা অনুযায়ী উপযুক্ত মডেল তৈরি করা সম্ভব।
Java Persistence API (JPA) অবজেক্ট-ওরিয়েন্টেড প্রোগ্রামিং মডেলের একটি গুরুত্বপূর্ণ বৈশিষ্ট্য হল Inheritance। এটি ডাটাবেসের টেবিল এবং জাভা ক্লাসের মধ্যে অবজেক্ট-ওরিয়েন্টেড উত্তরাধিকার (Inheritance) মডেল পরিচালনার জন্য ব্যবহৃত হয়। জাভার ইনহেরিটেন্স কনসেপ্টকে ডাটাবেসে রিফ্লেক্ট করতে JPA বিভিন্ন স্ট্র্যাটেজি প্রদান করে।
Inheritance কি?
Inheritance হল অবজেক্ট-ওরিয়েন্টেড প্রোগ্রামিংয়ের একটি মৌলিক বৈশিষ্ট্য, যা এক ক্লাসের বৈশিষ্ট্য (Attributes) এবং মেথড (Methods) আরেকটি ক্লাসে শেয়ার করার সুযোগ দেয়। JPA ইনহেরিটেন্সের মাধ্যমে, আমরা প্যারেন্ট ক্লাসের তথ্য একাধিক চাইল্ড ক্লাসের মধ্যে শেয়ার করতে পারি এবং সেগুলো ডাটাবেস টেবিলের মধ্যে সঠিকভাবে ম্যাপ করতে পারি।
JPA Inheritance এর প্রয়োজনীয়তা
- কোড পুনরায় ব্যবহারযোগ্য করা: প্যারেন্ট ক্লাসের সাধারণ বৈশিষ্ট্যগুলো চাইল্ড ক্লাসে ব্যবহার করা যায়।
- ডাটাবেস মডেলিং সহজতর করা: অবজেক্ট-ওরিয়েন্টেড ইনহেরিটেন্সের সমতুল্য একটি রিলেশনাল ডাটাবেস মডেল তৈরি করা।
- ডাটা সংগঠনের সুবিধা: অভিন্ন বৈশিষ্ট্যগুলো এক জায়গায় রাখা, যা ডাটার পুনরাবৃত্তি (Data Redundancy) কমায়।
- পরিচালনা সহজ করা: ইনহেরিটেড ক্লাসগুলোর মাধ্যমে ডাটাবেস অপারেশন পরিচালনা আরও কার্যকর হয়।
JPA Inheritance এর স্ট্র্যাটেজি
JPA-তে ইনহেরিটেন্স ব্যবস্থাপনার জন্য তিনটি স্ট্র্যাটেজি ব্যবহৃত হয়:
Single Table Strategy
একটি মাত্র টেবিলে সব প্যারেন্ট এবং চাইল্ড ক্লাসের তথ্য রাখা হয়। এটি দ্রুত এবং কার্যকর কিন্তু ডাটা রিডান্ডেন্সি বাড়তে পারে।
উদাহরণ:
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.STRING)
public class Employee {
@Id
private Long id;
private String name;
}
@Entity
public class FullTimeEmployee extends Employee {
private double salary;
}
@Entity
public class PartTimeEmployee extends Employee {
private double hourlyRate;
}
টেবিল গঠন:
| ID | NAME | TYPE | SALARY | HOURLY_RATE |
|---|---|---|---|---|
| 1 | Alice | FullTimeEmployee | 50000 | NULL |
| 2 | Bob | PartTimeEmployee | NULL | 20 |
Table Per Class Strategy
প্রতিটি ক্লাসের জন্য আলাদা টেবিল তৈরি হয়। এটি রিলেশনাল ডাটাবেসের জন্য আরও স্বচ্ছ, কিন্তু কার্যকারিতা কিছুটা কম হতে পারে।
উদাহরণ:
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Employee {
@Id
private Long id;
private String name;
}
@Entity
public class FullTimeEmployee extends Employee {
private double salary;
}
@Entity
public class PartTimeEmployee extends Employee {
private double hourlyRate;
}
টেবিল গঠন:
Employee (প্যারেন্ট টেবিল):
ID NAME 1 Alice 2 Bob FullTimeEmployee (চাইল্ড টেবিল):
ID SALARY 1 50000 PartTimeEmployee (চাইল্ড টেবিল):
ID HOURLY_RATE 2 20
Joined Strategy
প্যারেন্ট ক্লাস এবং চাইল্ড ক্লাসের জন্য আলাদা টেবিল তৈরি হয় এবং তাদের মধ্যে যোগসূত্র থাকে। এটি নরমালাইজড ডাটাবেস মডেল তৈরি করে এবং ডাটা রিডান্ডেন্সি কমায়।
উদাহরণ:
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Employee {
@Id
private Long id;
private String name;
}
@Entity
public class FullTimeEmployee extends Employee {
private double salary;
}
@Entity
public class PartTimeEmployee extends Employee {
private double hourlyRate;
}
টেবিল গঠন:
Employee (প্যারেন্ট টেবিল):
ID NAME 1 Alice 2 Bob FullTimeEmployee (চাইল্ড টেবিল):
ID SALARY 1 50000 PartTimeEmployee (চাইল্ড টেবিল):
ID HOURLY_RATE 2 20
কোন স্ট্র্যাটেজি কখন ব্যবহার করবেন?
- Single Table Strategy:
- যখন পারফরম্যান্স গুরুত্বপূর্ণ।
- সাধারণ ইনহেরিটেন্স কাঠামোর জন্য।
- Table Per Class Strategy:
- ছোট টেবিল এবং সহজ স্ট্রাকচার দরকার হলে।
- Joined Strategy:
- ডাটা রিডান্ডেন্সি কমানোর প্রয়োজন হলে এবং রিলেশনাল ডাটাবেসের সাথে মিলিয়ে কাজ করতে হলে।
সারাংশ
JPA Inheritance ডাটাবেস এবং জাভা অবজেক্টের মধ্যে ইনহেরিটেন্স মডেল তৈরি করতে গুরুত্বপূর্ণ ভূমিকা পালন করে। এটি ডাটাবেস মডেলিংকে আরও কার্যকর এবং অবজেক্ট-ওরিয়েন্টেড প্রোগ্রামিংয়ের সাথে সামঞ্জস্যপূর্ণ করে। Inheritance এর বিভিন্ন স্ট্র্যাটেজি ব্যবহার করে আপনি আপনার অ্যাপ্লিকেশনের প্রয়োজন অনুযায়ী ডাটাবেস ডিজাইন করতে পারেন।
স্প্রিং বুট এবং JPA (Java Persistence API) বিভিন্ন ধরণের ইনহেরিটেন্স স্ট্র্যাটেজি প্রদান করে। ইনহেরিটেন্স স্ট্র্যাটেজি ডেটাবেসে অবজেক্ট-ওরিয়েন্টেড সম্পর্ককে টেবিল ফর্ম্যাটে মানচিত্র করতে সাহায্য করে। JPA তিনটি প্রধান ইনহেরিটেন্স স্ট্র্যাটেজি প্রদান করে:
- Table-per-Class
- Single Table
- Joined Table
Table-per-Class Strategy
সংজ্ঞা
এই স্ট্র্যাটেজিতে প্রতিটি ক্লাসের জন্য একটি স্বতন্ত্র টেবিল তৈরি করা হয়। বেস ক্লাস এবং ডেরাইভড ক্লাসের ডেটা আলাদাভাবে সংরক্ষণ করা হয়।
বৈশিষ্ট্য
- প্রতিটি ক্লাসের জন্য আলাদা টেবিল।
- ডেটাবেসে সম্পর্কিত ডেটা রাখতে দ্রুত এবং সহজ।
- ডুপ্লিকেট কলাম থাকতে পারে।
কনফিগারেশন
Inheritance Type: InheritanceType.TABLE_PER_CLASS
উদাহরণ
import jakarta.persistence.*;
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Vehicle {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
// Getters and Setters
}
@Entity
public class Car extends Vehicle {
private int seatingCapacity;
// Getters and Setters
}
@Entity
public class Bike extends Vehicle {
private boolean hasCarrier;
// Getters and Setters
}
টেবিল গঠন
- Car Table:
id,name,seatingCapacity - Bike Table:
id,name,hasCarrier
Single Table Strategy
সংজ্ঞা
এই স্ট্র্যাটেজিতে সমস্ত ক্লাসের ডেটা একটি টেবিলে রাখা হয়। টেবিলটি একটি discriminator column ব্যবহার করে ডেটা আলাদা করে।
বৈশিষ্ট্য
- ডেটার জন্য শুধুমাত্র একটি টেবিল।
- স্টোরেজ দক্ষ।
- বড় টেবিলে অনেক নাল ভ্যালু থাকতে পারে।
কনফিগারেশন
Inheritance Type: InheritanceType.SINGLE_TABLE
উদাহরণ
import jakarta.persistence.*;
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "vehicle_type", discriminatorType = DiscriminatorType.STRING)
public abstract class Vehicle {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
// Getters and Setters
}
@Entity
@DiscriminatorValue("CAR")
public class Car extends Vehicle {
private int seatingCapacity;
// Getters and Setters
}
@Entity
@DiscriminatorValue("BIKE")
public class Bike extends Vehicle {
private boolean hasCarrier;
// Getters and Setters
}
টেবিল গঠন
- Vehicle Table:
id,name,vehicle_type,seatingCapacity,hasCarrier
Joined Table Strategy
সংজ্ঞা
এই স্ট্র্যাটেজিতে প্রতিটি ক্লাসের জন্য আলাদা টেবিল থাকে, তবে তাদের মধ্যে সম্পর্ক গঠন করার জন্য JOIN অপারেশন ব্যবহৃত হয়।
বৈশিষ্ট্য
- সম্পর্কিত ডেটা সংরক্ষণের জন্য কার্যকর।
- ডেটার রিডন্ডেন্সি (Redundancy) কম।
- কোয়েরির সময় জয়েন অপারেশন করার প্রয়োজন হয়।
কনফিগারেশন
Inheritance Type: InheritanceType.JOINED
উদাহরণ
import jakarta.persistence.*;
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Vehicle {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
// Getters and Setters
}
@Entity
public class Car extends Vehicle {
private int seatingCapacity;
// Getters and Setters
}
@Entity
public class Bike extends Vehicle {
private boolean hasCarrier;
// Getters and Setters
}
টেবিল গঠন
- Vehicle Table:
id,name - Car Table:
id,seatingCapacity - Bike Table:
id,hasCarrier
পার্থক্য
| বৈশিষ্ট্য | Table-per-Class | Single Table | Joined Table |
|---|---|---|---|
| সংরক্ষণ কৌশল | প্রতিটি ক্লাসের জন্য আলাদা টেবিল | একক টেবিলে সমস্ত ডেটা | সম্পর্কিত টেবিল ব্যবহার |
| ডেটার অখণ্ডতা | কম | কম | বেশি |
| স্টোরেজ দক্ষতা | কম | বেশি | মাঝারি |
| কোয়েরি জটিলতা | কম | সহজ | বেশি |
| নাল ভ্যালু সমস্যা | না | হ্যাঁ | না |
সারাংশ
Spring Boot এবং JPA-তে Table-per-Class, Single Table, এবং Joined Table ইনহেরিটেন্স স্ট্র্যাটেজি ব্যবহার করে ডেটাবেস সম্পর্ক গঠন এবং ডেটা সংরক্ষণ করা যায়। প্রতিটি স্ট্র্যাটেজির নিজস্ব সুবিধা এবং সীমাবদ্ধতা রয়েছে। আপনার প্রয়োজন অনুসারে স্ট্র্যাটেজি বেছে নেওয়া উচিত।
JPA Inheritance Mapping ব্যবহার করে আমরা ডাটাবেস টেবিলের মধ্যে Object-Oriented Programming এর Inheritance ধারণা প্রয়োগ করতে পারি। এটি বিশেষভাবে উপকারী যখন আমাদের কাছে Parent এবং Child ক্লাস থাকে এবং আমরা ডেটা টেবিলগুলোর মধ্যে সম্পর্ক তৈরি করতে চাই।
JPA বিভিন্ন স্ট্র্যাটেজি ব্যবহার করে Inheritance Mapping সম্পন্ন করে। এগুলো হলো:
- SINGLE_TABLE (ডিফল্ট স্ট্র্যাটেজি)
- TABLE_PER_CLASS
- JOINED
১. SINGLE_TABLE স্ট্র্যাটেজি
SINGLE_TABLE স্ট্র্যাটেজিতে Parent এবং Child ক্লাসের সব ডেটা একটি একক টেবিলে সংরক্ষিত হয়।
উদাহরণ
Entity ক্লাস (Parent এবং Child):
import jakarta.persistence.*;
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.STRING)
public abstract class Vehicle {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
// Getters and Setters
}
@Entity
@DiscriminatorValue("Car")
public class Car extends Vehicle {
private int seatCount;
// Getters and Setters
}
@Entity
@DiscriminatorValue("Bike")
public class Bike extends Vehicle {
private boolean hasCarrier;
// Getters and Setters
}
জেনারেট হওয়া টেবিল:
| id | name | type | seatCount | hasCarrier |
|---|---|---|---|---|
| 1 | Toyota | Car | 5 | NULL |
| 2 | Yamaha | Bike | NULL | true |
২. TABLE_PER_CLASS স্ট্র্যাটেজি
TABLE_PER_CLASS স্ট্র্যাটেজিতে Parent ক্লাস এবং প্রতিটি Child ক্লাসের জন্য আলাদা আলাদা টেবিল তৈরি হয়।
উদাহরণ
Entity ক্লাস (Parent এবং Child):
import jakarta.persistence.*;
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Vehicle {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
// Getters and Setters
}
@Entity
public class Car extends Vehicle {
private int seatCount;
// Getters and Setters
}
@Entity
public class Bike extends Vehicle {
private boolean hasCarrier;
// Getters and Setters
}
জেনারেট হওয়া টেবিল:
Car টেবিল:
| id | name | seatCount |
|---|---|---|
| 1 | Toyota | 5 |
Bike টেবিল:
| id | name | hasCarrier |
|---|---|---|
| 1 | Yamaha | true |
৩. JOINED স্ট্র্যাটেজি
JOINED স্ট্র্যাটেজিতে Parent ক্লাস এবং Child ক্লাসের জন্য আলাদা টেবিল তৈরি হয়, এবং তাদের মধ্যে একটি JOIN সম্পর্ক থাকে।
উদাহরণ
Entity ক্লাস (Parent এবং Child):
import jakarta.persistence.*;
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Vehicle {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
// Getters and Setters
}
@Entity
public class Car extends Vehicle {
private int seatCount;
// Getters and Setters
}
@Entity
public class Bike extends Vehicle {
private boolean hasCarrier;
// Getters and Setters
}
জেনারেট হওয়া টেবিল:
Vehicle টেবিল:
| id | name |
|---|---|
| 1 | Toyota |
| 2 | Yamaha |
Car টেবিল:
| id | seatCount |
|---|---|
| 1 | 5 |
Bike টেবিল:
| id | hasCarrier |
|---|---|
| 2 | true |
Service এবং Repository উদাহরণ
Repository:
import org.springframework.data.jpa.repository.JpaRepository;
public interface VehicleRepository extends JpaRepository<Vehicle, Long> {
}
Service:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class VehicleService {
@Autowired
private VehicleRepository vehicleRepository;
public void saveVehicles() {
Car car = new Car();
car.setName("Toyota");
car.setSeatCount(5);
vehicleRepository.save(car);
Bike bike = new Bike();
bike.setName("Yamaha");
bike.setHasCarrier(true);
vehicleRepository.save(bike);
}
}
Inheritance স্ট্র্যাটেজি বেছে নেওয়ার পরামর্শ
- SINGLE_TABLE: পারফরম্যান্স ভালো এবং টেবিল কম প্রয়োজন। তবে অনেক ক্ষেত্রেই NULL ভ্যালু তৈরি হয়।
- TABLE_PER_CLASS: আলাদা টেবিল প্রয়োজন এবং Parent ক্লাসের ডেটা Child টেবিলে মাইগ্রেট হয়।
- JOINED: ডেটা নরমালাইজড এবং ডেটার রিপিটেশন নেই, তবে
JOINঅপারেশনের কারণে স্লো হতে পারে।
সারাংশ
JPA Inheritance Mapping ব্যবহার করে Parent-Child সম্পর্কের ডেটা টেবিলের সঙ্গে মানিয়ে নেওয়া যায়। SINGLE_TABLE, TABLE_PER_CLASS, এবং JOINED স্ট্র্যাটেজির মধ্যে সঠিক একটি নির্বাচন অ্যাপ্লিকেশনের প্রয়োজন অনুযায়ী নির্ভর করে। প্রতিটি স্ট্র্যাটেজির নিজস্ব সুবিধা এবং সীমাবদ্ধতা রয়েছে।
Read more